package com.doubao.auth.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.doubao.auth.config.JwtConfig;
import com.doubao.auth.dto.JwtAuthResponse;
import com.doubao.auth.dto.LoginRequest;
import com.doubao.auth.dto.RefreshTokenRequest;
import com.doubao.auth.dto.RegisterRequest;
import com.doubao.auth.entity.AuthUser;
import com.doubao.auth.mapper.AuthUserMapper;
import com.doubao.auth.util.JwtUtils;
import com.doubao.common.result.Result;
import com.doubao.common.utils.RedisTemplateFactory;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
@Slf4j
public class AuthService {

    private final AuthenticationManager authenticationManager;
    private final JwtUtils jwtUtils;
    private final PasswordEncoder passwordEncoder;
    private final AuthUserMapper authUserMapper;
    private RedisTemplate<String, String> redisTemplate;
    private final JwtConfig jwtConfig;
    private final PhoneAuthService phoneAuthService; // 添加PhoneAuthService依赖

    private static final String REFRESH_TOKEN_KEY_PREFIX = "refresh:token:";

    // 内存缓存，用于Redis不可用时的备用存储
    private final Map<String, String> localRefreshTokenCache = new HashMap<>();

    @PostConstruct
    public void init() {
        this.redisTemplate = RedisTemplateFactory.getStringRedisTemplate();
        log.info("AuthService使用RedisTemplateFactory获取StringRedisTemplate");
    }

    /**
     * 用户注册
     */
    @Transactional
    public Result<Void> register(RegisterRequest registerRequest) {
        // 校验用户名是否存在
        LambdaQueryWrapper<AuthUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AuthUser::getUsername, registerRequest.getUsername());
        if (authUserMapper.selectCount(queryWrapper) > 0) {
            return Result.failed("用户名已存在");
        }

        // 校验手机号是否存在
        if (StringUtils.isNotBlank(registerRequest.getPhone())) {
            queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(AuthUser::getPhone, registerRequest.getPhone());
            if (authUserMapper.selectCount(queryWrapper) > 0) {
                return Result.failed("手机号已存在");
            }
        }

        // 校验邮箱是否存在
        if (StringUtils.isNotBlank(registerRequest.getEmail())) {
            queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(AuthUser::getEmail, registerRequest.getEmail());
            if (authUserMapper.selectCount(queryWrapper) > 0) {
                return Result.failed("邮箱已存在");
            }
        }

        // 校验密码是否一致
        if (!registerRequest.getPassword().equals(registerRequest.getConfirmPassword())) {
            return Result.failed("两次输入的密码不一致");
        }

        // 创建用户
        AuthUser user = new AuthUser();
        user.setUuid(UUID.randomUUID().toString().replace("-", ""));
        user.setUsername(registerRequest.getUsername());
        user.setPassword(passwordEncoder.encode(registerRequest.getPassword()));
        user.setNickname(StringUtils.isNotBlank(registerRequest.getNickname()) ?
                registerRequest.getNickname() : registerRequest.getUsername());
        user.setPhone(registerRequest.getPhone());
        user.setEmail(registerRequest.getEmail());
        user.setStatus(1); // 正常状态
        user.setDeleted(0); // 未删除
        user.setVipStatus(0); // 非VIP
        user.setLoginCount(0); // 登录次数
        user.setTotalTokensBalance(99999999); // 初始余额设为0，由token服务统一初始化
        user.setTotalTokensUsed(100L); // 初始token使用量
        user.setCreatedAt(LocalDateTime.now());
        user.setUpdatedAt(LocalDateTime.now());

        authUserMapper.insert(user);
        return Result.success();
    }

    /**
     * 用户登录
     */
    public Result<JwtAuthResponse> login(LoginRequest loginRequest) {
        try {
            // 验证用户名密码
            Authentication authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            loginRequest.getUsername(),
                            loginRequest.getPassword()
                    )
            );
            SecurityContextHolder.getContext().setAuthentication(authentication);

            // 获取用户信息
            LambdaQueryWrapper<AuthUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(AuthUser::getUsername, loginRequest.getUsername());
            AuthUser user = authUserMapper.selectOne(queryWrapper);

            // 生成令牌，添加userId到claims中
            Map<String, Object> claims = new HashMap<>();
            claims.put("userId", user.getId().toString());
            String token = jwtUtils.generateToken(loginRequest.getUsername(), claims);
            String refreshToken = jwtUtils.generateRefreshToken(loginRequest.getUsername());

            // 将刷新令牌存入Redis，设置7天过期
            try {
                redisTemplate.opsForValue().set(
                        REFRESH_TOKEN_KEY_PREFIX + loginRequest.getUsername(),
                        refreshToken,
                        jwtConfig.getRefreshExpiration(),
                        TimeUnit.DAYS
                );
            } catch (RedisConnectionFailureException e) {
                // Redis连接失败，使用内存缓存作为备用
                log.warn("Redis连接失败，使用内存缓存存储刷新令牌: {}", loginRequest.getUsername());
                localRefreshTokenCache.put(loginRequest.getUsername(), refreshToken);
            }

            // 更新用户最后登录信息
            user.setLastLoginTime(LocalDateTime.now());
            user.setLastLoginIp(loginRequest.getIp());
            user.setLoginCount(user.getLoginCount() + 1);
            authUserMapper.updateById(user);

            // 构建响应对象
            JwtAuthResponse authResponse = new JwtAuthResponse();
            authResponse.setToken(token);
            authResponse.setRefreshToken(refreshToken);
            authResponse.setUserId(user.getId());
            authResponse.setUsername(user.getUsername());
            authResponse.setNickname(user.getNickname());
            authResponse.setAvatar(user.getAvatar());
            authResponse.setVipStatus(user.getVipStatus());

            return Result.success(authResponse);
        } catch (Exception e) {
            log.error("登录失败", e);
            return Result.failed("用户名或密码错误");
        }
    }

    /**
     * 刷新令牌
     */
    public Result<JwtAuthResponse> refreshToken(RefreshTokenRequest refreshTokenRequest) {
        try {
            String refreshToken = refreshTokenRequest.getRefreshToken();
            if (!jwtUtils.validateToken(refreshToken)) {
                return Result.failed("无效的刷新令牌");
            }

            String username = jwtUtils.getUsernameFromToken(refreshToken);
            String storedRefreshToken = null;

            try {
                // 尝试从Redis获取刷新令牌
                storedRefreshToken = redisTemplate.opsForValue().get(REFRESH_TOKEN_KEY_PREFIX + username);
            } catch (RedisConnectionFailureException e) {
                // Redis连接失败，从本地缓存或PhoneAuthService获取
                log.warn("Redis连接失败，尝试从备用缓存获取刷新令牌");
                storedRefreshToken = localRefreshTokenCache.get(username);
                if (storedRefreshToken == null) {
                    storedRefreshToken = phoneAuthService.getRefreshToken(username);
                }
            }

            if (storedRefreshToken == null || !storedRefreshToken.equals(refreshToken)) {
                return Result.failed("刷新令牌已过期");
            }

            // 获取用户信息
            LambdaQueryWrapper<AuthUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(AuthUser::getUsername, username);
            AuthUser user = authUserMapper.selectOne(queryWrapper);
            if (user == null) {
                return Result.failed("用户不存在");
            }

            // 生成新的访问令牌 - 修改为使用userId
            String newToken = jwtUtils.generateToken(username, user.getId());

            // 构建响应对象
            JwtAuthResponse authResponse = new JwtAuthResponse();
            authResponse.setToken(newToken);
            authResponse.setRefreshToken(refreshToken); // 刷新令牌保持不变
            authResponse.setUserId(user.getId());
            authResponse.setUsername(user.getUsername());
            authResponse.setNickname(user.getNickname());
            authResponse.setAvatar(user.getAvatar());
            authResponse.setVipStatus(user.getVipStatus());

            return Result.success(authResponse);
        } catch (Exception e) {
            log.error("刷新令牌失败", e);
            return Result.failed("刷新令牌失败");
        }
    }

    /**
     * 退出登录
     */
    public Result<Void> logout(String token) {
        try {
            if (StringUtils.isNotBlank(token) && token.startsWith(jwtConfig.getTokenPrefix())) {
                token = token.substring(jwtConfig.getTokenPrefix().length());
            }

            if (jwtUtils.validateToken(token)) {
                String username = jwtUtils.getUsernameFromToken(token);
                try {
                    redisTemplate.delete(REFRESH_TOKEN_KEY_PREFIX + username);
                } catch (RedisConnectionFailureException e) {
                    // Redis连接失败，清除内存缓存
                    log.warn("Redis连接失败，仅清除内存缓存中的刷新令牌");
                    localRefreshTokenCache.remove(username);
                }
            }

            return Result.success();
        } catch (Exception e) {
            log.error("退出登录失败", e);
            return Result.success(); // 即使发生异常，也视为登出成功
        }
    }

    /**
     * 获取刷新令牌，用于其他服务调用
     */
    public String getRefreshToken(String username) {
        try {
            return redisTemplate.opsForValue().get(REFRESH_TOKEN_KEY_PREFIX + username);
        } catch (RedisConnectionFailureException e) {
            // Redis连接失败，从内存缓存获取
            log.warn("Redis连接失败，从内存缓存获取刷新令牌: {}", username);
            return localRefreshTokenCache.get(username);
        }
    }
}